﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Publicuse.Entity;
using Publicuse.Interface;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Publicuse.Service
{
    public class BaseEfCoreService : IBaseEFCoreService
    {
        protected DbContext dbContext { get; private set; }

        public BaseEfCoreService(DbContext dbContext)
        {
            this.dbContext = dbContext;
        }

        private void InitDB(out string msg, Action action, bool iscommit = true)
        {
            msg = string.Empty;
            if (iscommit)
            {
                using (var tran = this.dbContext.Database.BeginTransaction())
                {
                    try
                    {
                        action.Invoke();
                        this.dbContext.SaveChanges();
                        tran.Commit();
                    }
                    catch (Exception ex)
                    {
                        msg = ex.Message;
                        if (ex.InnerException != null)
                        {
                            msg += "," + ex.InnerException.Message;
                        }
                        if (tran != null)
                        {
                            tran.Rollback();
                        }
                    }
                }
            }
            else
            {
                try
                {
                    action.Invoke();
                }
                catch (Exception ex)
                {
                    msg = ex.Message;
                    if (ex.InnerException != null)
                    {
                        msg += "," + ex.InnerException.Message;
                    }
                }
            }

        }

        /// <summary>
        /// 增加
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        void IBaseEFCoreService.Insert<T>(T entity, out string msg)
        {
            this.InitDB(out msg, () =>
            {
                this.dbContext.Set<T>().Attach(entity);
                this.dbContext.Set<T>().Add(entity);
            });
        }

        /// <summary>
        /// 增加
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        void IBaseEFCoreService.Insert<T>(IEnumerable<T> entity, out string msg)
        {
            this.InitDB(out msg, () =>
            {
                this.dbContext.Set<T>().AddRange(entity);
            });
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <param name="msg"></param>
        /// <exception cref="NotImplementedException"></exception>
        void IBaseEFCoreService.Delete<T>(T t, out string msg)
        {
            msg = string.Empty;
            this.InitDB(out msg, () =>
            {
                var entity = this.dbContext.Set<T>();
                entity.Attach(t);
                entity.Remove(t);
            }, true);
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <param name="msg"></param>
        void IBaseEFCoreService.Delete<T>(int id, out string msg)
        {
            msg = string.Empty;
            this.InitDB(out msg, () =>
              {
                  T t = this.dbContext.Set<T>().Find(id);
                  if (t != null)
                  {
                      var entity = this.dbContext.Set<T>();
                      entity.Attach(t);
                      entity.Remove(t);
                  }
              }, true);
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <param name="msg"></param>
        /// <exception cref="NotImplementedException"></exception>
        void IBaseEFCoreService.Delete<T>(IEnumerable<T> entitys, out string msg)
        {
            msg = string.Empty;
            this.InitDB(out msg, () =>
            {
                foreach (var item in entitys)
                {
                    this.dbContext.Set<T>().Attach(item);
                }
                this.dbContext.Set<T>().RemoveRange(entitys);
            }, true);
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        void IBaseEFCoreService.Update<T>(T entity, out string msg)
        {
            msg = string.Empty;
            this.InitDB(out msg, () =>
            {
                this.dbContext.Set<T>().Attach(entity);
                this.dbContext.Entry<T>(entity).State = EntityState.Modified;
            }, true);
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="id"></param>
        /// <param name="msg"></param>
        void IBaseEFCoreService.Update<T>(T t, int id, out string msg)
        {
            msg = string.Empty;
            this.InitDB(out msg, () =>
            {
                var entity = this.dbContext.Set<T>().Find(id);
                var entitydbSet = this.dbContext.Set<T>();
                entitydbSet.Attach(entity);
                var index = 0;
                foreach (var item in t.GetType().GetProperties())
                {
                    var itemValue = item.GetValue(t);
                    if (itemValue != null)
                    {
                        foreach (var itemb in entity.GetType().GetProperties())
                        {
                            if (item.Name == itemb.Name)
                            {
                                if (index == 0)
                                {
                                    index++;
                                    continue;
                                }
                                else
                                {
                                    itemb.SetValue(entity, itemValue);
                                    break;
                                }
                            }
                        }
                    }
                }
            }, true);
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        void IBaseEFCoreService.Update<T>(IEnumerable<T> tList, out string msg)
        {
            msg = string.Empty;
            this.InitDB(out msg, () =>
            {
                foreach (var item in tList)
                {
                    this.dbContext.Set<T>().Attach(item);
                    this.dbContext.Entry<T>(item).State = EntityState.Modified;
                }
            }, true);
        }


        /// <summary>
        /// 查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        T IBaseEFCoreService.FindByID<T>(string id, out string msg)
        {
            T result = default(T);
            this.InitDB(out msg, () =>
            {
                result = this.dbContext.Set<T>().Find(Convert.ToInt32(id));
            }, false);
            return result;
        }

        /// <summary>
        /// 查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="S"></typeparam>
        /// <param name="funcWhere"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="funcOrder"></param>
        /// <param name="msg"></param>
        /// <param name="isAsc"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        PageResult<T> IBaseEFCoreService.QueryPage<T, S>(Expression<Func<T, bool>> funcWhere, int pageIndex, int pageSize, Expression<Func<T, S>> funcOrder, out string msg, bool isAsc)
        {
            msg = string.Empty;
            PageResult<T> result = new PageResult<T>()
            {
                PageIndex = pageIndex,
                PageSize = pageSize,
            };
            this.InitDB(out msg, () =>
            {
                var list = this.dbContext.Set<T>().AsQueryable<T>();
                if (funcWhere != null)
                    list = list.Where<T>(funcWhere);

                if (isAsc)
                    list = list.OrderBy(funcOrder);
                else
                    list = list.OrderByDescending(funcOrder);

                result.DataList = list.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
                result.TotalCount = list.Count();
            }, true);
            return result;
        }

        /// <summary>
        /// 查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        IQueryable<T> IBaseEFCoreService.Query<T>(Expression<Func<T, bool>> expression, out string msg)
        {
            msg = string.Empty;
            IQueryable<T> result = null;
            this.InitDB(out msg,() =>
            {
                result = this.dbContext.Set<T>().Where<T>(expression);
            }, false);
            return result;
        }

        /// <summary>
        /// 查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <param name="sql"></param>
        /// <param name="msg"></param>
        /// <param name="list"></param>
        /// <param name="parameters"></param>
        void IBaseEFCoreService.ExecuteQuery<T>(T entity,string sql,out string msg, out List<T> list, params object[] parameters)
        {
            msg = string.Empty;
            List<T> resultList = new List<T>();
            this.InitDB(out msg, () =>
            {
                using (var con = dbContext.Database.GetDbConnection())
                {
                    using (var com = con.CreateCommand())
                    {
                        com.CommandText = sql;
                        if (parameters != null)
                            com.Parameters.AddRange(parameters);

                        con.Open();
                        var dr = com.ExecuteReader(CommandBehavior.Default);
                        while (dr.Read())
                        {
                            for (var i = 0; i < dr.FieldCount; i++)
                            {
                                var columnName = dr.GetName(i);
                                var val = dr.GetFieldValue<object>(i);

                                var property = entity.GetType().GetProperty(columnName);
                                if (val!=DBNull.Value)
                                {
                                    property?.SetValue(entity, val);
                                }
                            }
                            resultList.Add(entity);
                        }
                    }
                }
            }, false);
            list = resultList;
        }

        /// <summary>
        /// 执行SQL
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <param name="msg"></param>
        /// <exception cref="NotImplementedException"></exception>
        void IBaseEFCoreService.ExecuteSql<T>(string sql, out string msg, params object[] parameters)
        {
            msg = string.Empty;
            this.InitDB(out msg, () =>
            {
                this.dbContext.Database.ExecuteSqlRaw(sql, parameters);
            }, true);
        }

        /// <summary>
        /// 是否资源
        /// </summary>
        public void Dispose()
        {
            if (this.dbContext != null)
                this.dbContext.Dispose();
        }

    }
}
